#ifndef GAME_ANIMATION_MAKE_TREE_H
#define GAME_ANIMATION_MAKE_TREE_H
//
// Game Animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <animation/configuration.h>

#include<OpenTissue/core/math/noise/noise_improved_perlin.h>
#include<OpenTissue/core/math/math_random.h>

#include <queue>
#include <vector>
#include <cassert>

namespace animation
{
  /**
  * Plant grass clump.
  *
  * @param idx             Index of grass clump.
  * @param position        The surface point where the grass is planted.
  * @param normal          surface normal at the point where the grass normal is planted.
  * @param halfwidth       parameter to control grass width.
  * @param height          parameter to control grass height.
  * @param u0              u-texture coord of lower left corner of grass quad.
  * @param v0              v-texture coord of lower left corner of grass quad.
  * @param u1              u-texture coord of upper-right corner of grass quad.
  * @param v1              v-texture coord of upper-right corner of grass quad.
  */

  template<typename vector3_type,typename real_type,typename geometry_type>
    inline void plant_tree(
      unsigned int const & idx
    , vector3_type const &  position
    , vector3_type const &  normal
    , real_type const & halfwidth
    , real_type const & height
    , real_type const &u0
    , real_type const &v0
    , real_type const &u1
    , real_type const &v1
    , geometry_type & field
    )
  {
    typedef typename geometry_type::vertex_type  vertex_type;

    assert(height>0.0    || !"plant_tree(): Illegal grass height size");
    assert(halfwidth>0.0 || !"plant_tree(): Illegal grass width size");
    unsigned int first_vertex_idx = idx*4;
    vertex_type & p0 = field.get_vertex(first_vertex_idx + 0);
    vertex_type & p1 = field.get_vertex(first_vertex_idx + 1);
    vertex_type & p2 = field.get_vertex(first_vertex_idx + 2);
    vertex_type & p3 = field.get_vertex(first_vertex_idx + 3);
    //
    // Grass Quad/Billboard Layout
    //
    //
    //  (u0,v1)            (u1,v1)
    //
    //   i+0  +----------+ i+1
    //        |          |
    //        |          |
    //        |          |
    //        |          |           / \
    //        |   plant point         |
    //        |    |     |            | y-axis
    //    i+2 +----*-----+ i+3        |
    //
    //  (u0,v0)            (u1,v0)
    //
    //      --- x axis --->
    //
    p0.m_coord = position;
    p1.m_coord = position;
    p2.m_coord = position;
    p3.m_coord = position;

    //--- Set normals so grass is lit in the same way
    //--- as surface
    //---
    //--- smooth interpolated normal of the surface at the planting point!
    //---
    p0.m_normal = normal;
    p1.m_normal = normal;
    p2.m_normal = normal;
    p3.m_normal = normal;
    //--- For color tinting or shifting
    p0.m_color[0] = 0.3; p0.m_color[1] = 0.9; p0.m_color[2] = 0.1; p0.m_color[3] = 0.25;
    p1.m_color[0] = 0.3; p1.m_color[1] = 0.9; p1.m_color[2] = 0.1; p1.m_color[3] = 0.25;
    p2.m_color[0] = 0.3; p2.m_color[1] = 0.9; p2.m_color[2] = 0.1; p2.m_color[3] = 0.25;
    p3.m_color[0] = 0.3; p3.m_color[1] = 0.9; p3.m_color[2] = 0.1; p3.m_color[3] = 0.25;
    //--- Use  texcoords to select the wanted subregion of the grass
    //--- texture atlas
    p0.m_tex0[0] = u0;  p0.m_tex0[1] = v1;
    p1.m_tex0[0] = u1;  p1.m_tex0[1] = v1;
    p2.m_tex0[0] = u0;  p2.m_tex0[1] = v0;
    p3.m_tex0[0] = u1;  p3.m_tex0[1] = v0;
    //---
    //--- Corner offsets of planting point, i.e. the vertex program is
    //---
    //---  corner = plating_point + texcoord2.x*right_vector + texcoord2.y*up_vector
    //---
    //--- The right_vector (point to the right of the camera in wcs) and up_vector
    //--- (yielding the up direction of the camera in wcs) are uniforms
    //---
    p0.m_tex1[0] = -halfwidth;  p0.m_tex1[1] = height;
    p1.m_tex1[0] =  halfwidth;  p1.m_tex1[1] = height;
    p2.m_tex1[0] = -halfwidth;  p2.m_tex1[1] = 0;
    p3.m_tex1[0] =  halfwidth;  p3.m_tex1[1] = 0;

    //---- setup special effects data, winddirection and grass stiffness!!!
    p0.m_tex2[0] = 1.0; p0.m_tex2[1] = 0.0; p0.m_tex2[2] = 0.0; p0.m_tex2[3] = height*0.25;
    p1.m_tex2[0] = 1.0; p1.m_tex2[1] = 0.0; p1.m_tex2[2] = 0.0; p1.m_tex2[3] = height*0.25;
    p2.m_tex2[0] = 1.0; p2.m_tex2[1] = 0.0; p2.m_tex2[2] = 0.0; p2.m_tex2[3] = height*0.25;
    p3.m_tex2[0] = 1.0; p3.m_tex2[1] = 0.0; p3.m_tex2[2] = 0.0; p3.m_tex2[3] = height*0.25;

    unsigned int j = idx*6;
    field.get_index(j+0) = first_vertex_idx+0;
    field.get_index(j+1) = first_vertex_idx+1;
    field.get_index(j+2) = first_vertex_idx+2;
    field.get_index(j+3) = first_vertex_idx+1;
    field.get_index(j+4) = first_vertex_idx+3;
    field.get_index(j+5) = first_vertex_idx+2;
  }

  /**
  * Grass Planting Algorithm.
  * This function plants grass clumps on a given height map surface. Currently
  * each triangle of the height map gets random 5 grass clumps.
  *
  *
  * @param surface       The height map surface.
  * @param field         Upon return holds the geometry layer of the resulting grass field.
  * @param halfwidth     The halfwidth of a single grass clump.
  * @param height        The height of a single grass clump.
  */
  template<typename list_type,typename geometry_type,typename real_type>
    inline void make_tree(
      list_type &points
    , geometry_type & field
    , real_type halfwidth
    , real_type height
    , geometry_type & planting_points)
  {
    typedef typename geometry_type::vertex_type          vertex_type;
    typedef typename geometry_type::vector3_type         vector3_type;


    //--- First determine planting positions of all grass clumps.
    OpenTissue::math::Random<real_type> random(0.0f,1.0f);
    std::vector<vector3_type> positions;
    std::vector<vector3_type> normals;
	srand(100);//To insure that the randomness is always the same.
	bool ty=true;
	for(list_type::iterator p=points.begin();p!=points.end();){
		
		vector3_type pos=p->pos;
		if(pos(2)<0.0){
			++p;
			continue;
		}	
		int placer=rand()%10000;

		if((pos(2)>=0.0&&placer<9990)){
			++p;
			continue;

		}	

		bool plant=true;
		//check for closeness.
		for(std::vector<vector3_type>::iterator t=positions.begin();t!=positions.end();t++){
			if(distance(pos,*t)<halfwidth){
				plant=false;
				break;
			}
		}

		if(!plant)continue;
        positions.push_back(pos);
		vertex_type pv;
		pv.m_coord=pos;

		/*tree type switcher*/
		pv.m_tex0[0]=(ty)?0.0:1.0;
		ty=!ty;

		planting_points.m_vertices.push_back(pv);
        normals.push_back(p->nor);
		for(list_type::iterator i=points.begin();i!=p;){
			if(distance(pos,i->pos)<0.1){
				points.erase(i++);
			}else{
				++i;
			}
		}
		list_type::iterator i=p;
		i++;
		for(;i!=points.end();){
			if(distance(pos,i->pos)<0.1){
				points.erase(i++);
			}else{
				++i;
			}
		}
		points.erase(p++);
    }
    //--- Make sure that we have allocated space for all the grass clump geometries.
    unsigned int N = positions.size();
    if(field.vertices() != N*4)
      field = geometry_type(N*4,N*6);

    //--- Finally we can plant all the grass clumps.
    for(unsigned int i=0;i<N;++i)
    {
      //--- Pick a set of texture coords in the texture atlas (assumed to be 1-by-4)
      real_type u0 =(i%2)*0.5;
      real_type v0 = 0;
      real_type u1 = 0.5+(i%2)*0.5;
      real_type v1 = 1;
	  real_type scale=0.8+((float)(rand()%100))/100.0*0.20;
	  
      plant_tree(
        i
        , positions[i]
        , normals[i]
        , halfwidth*scale
          , height*scale
          , u0
          , v0
          , u1
          , v1
          , field
          );
    }
  }

} // namespace animation

// GAME_ANIMATION_MAKE_GRASS_H
#endif
